package xj.model.uml;

import static xj.model.uml.UMLModelConstants.ROLE_STATE;
import static xj.model.uml.UMLModelConstants.ROLE_TRANSITION;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import xj.meta.ModelElement;

public class StateDiagram extends UMLDiagram {

  public StateDiagram() {
    setType(DiagramType.State_Machine_Diagram);
  }

  public StateDiagram(String name) {
    super(name);
    setType(DiagramType.State_Machine_Diagram);
  }

  @Override
  public boolean checkAllowedEdge(ModelElement m) {
    if (m != null) { 
      if (m instanceof Transition) { 
	return true;
      } else if (m instanceof UMLAssociation) { 
	UMLAssociation a = (UMLAssociation) m;
	if (a.getType() == UMLAssociation.AssociationType.Notes_Link) { 
	  return true;
	}
      }
    }       
    return false; 
  }

  @Override
  public boolean checkAllowedNode(ModelElement m) { 
    if (m != null && 
	(m instanceof State ||
	 m instanceof Note)) {
      return true;
    }
    return false; 
  }

  @Override
  public boolean checkAllowSubnode(ModelElement parentModel, 
				   ModelElement nodeModel) {
    if (parentModel instanceof State) { 
      State s = (State) parentModel;
      State.StateType stype = s.getType();
      return (nodeModel instanceof State && 
	      (stype == State.StateType.State_Machine || 
	       stype == State.StateType.Hyper_State || 
	       stype == State.StateType.Orthogonal_State ||
	       stype == State.StateType.Orthogonal_Region)); 
    } else if (parentModel instanceof StateMachine) { 
      return (nodeModel instanceof State);
    }
    return false; 
  }

  public void addState(State s) {
    if (s != null) {
      states.add(s);
      addOwnedElement(s, ROLE_STATE);
    }
  }

  public void removeState(State s) {
    if (s != null) {
      states.remove(s);
      removeOwnedElement(s);
    }
  }

  public Set<State> getStates() {
    return states;
  }

  public void addTransition(Transition t) {
    if (t != null) {
      transitions.add(t);
      addOwnedElement(t, ROLE_TRANSITION);
    }
  }

  public void removeTransition(Transition t) {
    if (t != null) {
      transitions.remove(t);
      removeOwnedElement(t);
    }
  }

  public Set<Transition> getTransitions() {
    return transitions;
  }

  @Override
  public void deconstruct() {
    super.deconstruct();
    states.clear();
    transitions.clear();
  }

  @Override
  public void add(ModelElement parent, ModelElement e, Object arg) {
    if (e != null) {
      if (e instanceof State) {
	if (parent instanceof HyperState) {
	  HyperState ps = (HyperState) parent;
	  ps.addState((State) e);
	} else if (parent instanceof OrthogonalState) {
	  OrthogonalState os = (OrthogonalState) parent;
	  int i = 0;
	  if (arg instanceof Integer) {
	    i = ((Integer) arg).intValue();
	  }
	  os.addState(i, (State) e);
	} else {
	  addState((State) e);
	}
      } else if (e instanceof Transition) {
	Transition t = (Transition) e;
	ModelElement left = t.getLeftElement();
	ModelElement right = t.getRightElement();
	if (left instanceof State && right instanceof State) {
	  ModelElement ancestor = null;
	  if (left == right) {
	    ancestor = left.getOwner();
	  } else {
	    ancestor = findLeastCommonAncestor(left, right);
	  }
	  while (ancestor != null
		 && !(ancestor instanceof HyperState || ancestor instanceof UMLDiagram)) {
	    ancestor = ancestor.getOwner();
	  }

	  if (ancestor != null) {
	    parent = ancestor;
	  }
	}

	if (parent instanceof HyperState) {
	  HyperState ps = (HyperState) parent;
	  ps.addTransition(t);
	} else {
	  addTransition(t);
	}
      } else {
	super.add(parent, e, arg);
      }
    }
  }

  @Override
  public Object clone() throws CloneNotSupportedException {
    StateDiagram hs = (StateDiagram) super.clone();

    hs.states = new HashSet<State>();
    Iterator<State> iter1 = states.iterator();
    while (iter1.hasNext()) {
      State s = iter1.next();
      hs.addState((State) s.clone());
    }

    hs.transitions = new HashSet<Transition>();
    Iterator<Transition> iter2 = transitions.iterator();
    while (iter2.hasNext()) {
      Transition t = iter2.next();
      hs.addTransition((Transition) t.clone());
    }

    return hs;
  }

  protected Set<State> states = new HashSet<State>();

  protected Set<Transition> transitions = new HashSet<Transition>();

}
